package cn.apthink.schedule;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import cn.apthink.calendar.Department;
import cn.apthink.calendar.DepartmentCalendarHelper;
import cn.apthink.calendar.DepartmentHelper;
import cn.apthink.calendar.WeekTemplateDetail;
import cn.apthink.calendar.WorkCalendar;
import cn.apthink.utility.DateUtil;
import cn.apthink.utility.Util;
import lombok.Data;

@Data
public class ScheduleTask implements Runnable {
	private EvaluationHelper evaluationHelper;
	private List<Soluation> soluations;
	private SoluationHelper soluationHelper;

	private List<Plan> plans;
	private List<Line> lines;
	private LocalDate startDate;
	private int runMillSeconds = 500;
	private String name;

	/**
	 * 
	 * @param name 排产任务名
	 * @param soluationSize 方案队列长度
	 * @param runTimeSecond 排产时长（秒）
	 */
	public ScheduleTask(String name, int soluationSize, int runMillSeconds) {
		this.soluationHelper = new SoluationHelper(soluationSize);
		this.runMillSeconds = runMillSeconds;
		this.name = name;
	}

	public void removeUnlockPlans() {
		for (Line line : lines) {
			line.removeUnlockPlans();
		}
	}

	public void changePlans(List<String> ids) {
		List<Plan> result = new ArrayList<Plan>();
		int index1 = Util.randInt(0, ids.size());
		int index2 = Util.randInt(0, ids.size());
		for (int i = 0, l = ids.size(); i < l; i++) {
			String id;
			if (i == index1) {
				id = ids.get(index2);
			} else if (i == index2) {
				id = ids.get(index1);
			} else {
				id = ids.get(i);
			}
			Plan p = plans.stream().filter(x -> {
				return x.getId().equals(id);
			}).findFirst().get();
			result.add(p);
		}
		setPlans(result);
	}

	private List<PlanKPI> preSchedule(Plan plan) {
		List<PlanKPI> result = new ArrayList<PlanKPI>();
		for (Line line : lines) {
			result.add(line.preAddPlan(plan, evaluationHelper.getContinueDays()));
		}
		return result;
	}

	private List<PlanKPI> schedule() {
		removeUnlockPlans();
		List<PlanKPI> lstKPI = new ArrayList<PlanKPI>();
		for (int i = 0, l = plans.size(); i < l; i++) {
			Plan p = plans.get(i);
			List<PlanKPI> ks = preSchedule(p);
			PlanKPI k = evaluationHelper.selectDepartment(ks);
			p.setScore(k.getScore());
			Line line = lines.stream().filter(x -> {
				return x.getId().equals(k.getDepartmentId());
			}).findFirst().get();
			line.addPlan(p);
			lstKPI.add(k);
		}
		return lstKPI;
	}

	//David: 根据现有计划排产获取初始方案结果，并刷新列表中计划排产信息
	public Soluation getInitSoluation() {
		List<PlanKPI> lstKPI = new ArrayList<PlanKPI>();
		for (int i = 0, l = plans.size(); i < l; i++) {
			Line line;
			PlanKPI pk;
			Plan plan = plans.get(i);
			List<PlanKPI> pks = preSchedule(plan);
			//已排直接评估，未排预排后评估
			if (Util.isEmpty(plan.getDepartmentId())) {
				pk = evaluationHelper.selectDepartment(pks);
				line = lines.stream().filter(x -> {
					return x.getId().equals(pk.getDepartmentId());
				}).findFirst().get();
			} else {
				evaluationHelper.evaluation(pks);
				pk = pks.stream().filter(x->{
					return x.getDepartmentId().equals(plan.getDepartmentId());
				}).findFirst().get();
				line = lines.stream().filter(x -> {
					return x.getId().equals(plan.getDepartmentId());
				}).findFirst().get();
			}
			line.addPlan(plan);
			lstKPI.add(pk);
		}
		Soluation soluation = new Soluation();
		soluation.setPlanKPIs(lstKPI);	
		return soluation;
	}

	@Override
	public void run() {
		soluationHelper.init();
		long s = System.currentTimeMillis() + runMillSeconds;
		while (true) {
			List<PlanKPI> pk = schedule();
			Soluation soluation = new Soluation();
			soluation.setPlanKPIs(pk);
			soluationHelper.add(soluation);
			if (s < System.currentTimeMillis())
				break;
		}
		soluations = soluationHelper.topSoluations();
	}

	public void setStartDate(LocalDate startDate) {
		if (lines == null)
			return;
		for (Line line : lines) {
			line.setValidStartDate(startDate);
		}
		this.startDate = startDate;
	}

	public void setLines(List<Line> lines) {
		this.lines = lines;
		if (startDate != null) {
			for (Line line : this.lines) {
				line.setValidStartDate(startDate);
			}
		}
	}

	public static ScheduleTask testData(String name, int soluationSize, int runMillSeconds) {
		List<Department> lstDepartment = new ArrayList<Department>();
		lstDepartment.add(new Department("factory", null, 8));
		lstDepartment.add(new Department("line1", "factory", 2));
		lstDepartment.add(new Department("line2", "factory", 2));
		lstDepartment.add(new Department("line3", "factory", 2));
		lstDepartment.add(new Department("line4", "factory", 2));
		lstDepartment.add(new Department("line5", "factory", 2));
		lstDepartment.add(new Department("line6", "factory", 2));
		lstDepartment.add(new Department("line7", "factory", 2));
		lstDepartment.add(new Department("line8", "factory", 2));
		lstDepartment.add(new Department("line9", "factory", 2));
		lstDepartment.add(new Department("line10", "factory", 2));

		List<Product> lstProduct = Product.testDatas();

		List<Efficiency> lstEfficiency = new ArrayList<Efficiency>();
		lstEfficiency.add(new Efficiency("line1", "p1", 0, 0.7));
		lstEfficiency.add(new Efficiency("line2", "p1", 0, 0.7));
		lstEfficiency.add(new Efficiency("line3", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("line4", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("line5", "p1", 0, 0.7));
		lstEfficiency.add(new Efficiency("line6", "p1", 0, 0.7));
		lstEfficiency.add(new Efficiency("line7", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("line8", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("line9", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("line10", "p1", 0, 0.8));
		lstEfficiency.add(new Efficiency("factory", "p", 0, 0.6));

		List<WorkCalendar> lstWorkCalendar = new ArrayList<WorkCalendar>();
		lstWorkCalendar.add(new WorkCalendar("factory", WorkCalendar.WeekTemplateDefault, "2024-10-10"));

		DepartmentCalendarHelper departmentCalendarHelper = new DepartmentCalendarHelper(lstDepartment, null,
				WeekTemplateDetail.testData(), lstWorkCalendar, null, null);
		departmentCalendarHelper.setRange(LocalDate.parse("2024-10-01"), LocalDate.parse("2025-10-01"));

		ProductHelper productHelper = new ProductHelper(lstProduct);
		DepartmentHelper departmentHelper = new DepartmentHelper(lstDepartment);
		EfficiencyHelper efficiencyHelper = new EfficiencyHelper(departmentHelper, productHelper, lstEfficiency);

		Evaluation evaluation = Evaluation.testData();
		EvaluationHelper evaluationHelper = new EvaluationHelper();
		evaluationHelper.setEvaluation(evaluation);

		List<Line> lines = new ArrayList<Line>();
		Line line = new Line("line1", 2);
//		List<Plan> ps = Plan.testDatas("l1");
//		ps.add(Plan.testData1("l1p4", "l1","2025-01-23","2025-01-25"));
//		ps.add(Plan.testData2("l1p5", "line1"));
//		line.setPlans(ps);
		lines.add(line);

		line = new Line("line2", 2);
		lines.add(line);
		line = new Line("line3", 2);
		lines.add(line);
		line = new Line("line4", 2);
		lines.add(line);
		line = new Line("line5", 2);
		lines.add(line);
		line = new Line("line6", 2);
		lines.add(line);
		line = new Line("line7", 2);
		lines.add(line);
		line = new Line("line8", 2);
		lines.add(line);
		line = new Line("line9", 2);
		lines.add(line);
		line = new Line("line10", 2);
		lines.add(line);

		lines.forEach(x -> {
			x.refresh(DateUtil.toDateTime("2025-01-01 00:00:00"));
			x.setCalendar(departmentCalendarHelper.getDepartmentCalendar(x.getId()));
			x.setEfficiencyHelper(efficiencyHelper);
		});

		ScheduleTask task = new ScheduleTask(name, soluationSize, runMillSeconds);
		task.setEvaluationHelper(evaluationHelper);
		task.setLines(lines);
		return task;
	}

}
